package demo.java.util.regex;

import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <li>Pattern: 正则表达式的编译表示形式。使用给定的正则表达式（以字符串形式）创建一个 Pattern 对象。
 * <li>Matcher: 解释模式并执行匹配操作的引擎。
 * <li>创建模式（Pattern）:Pattern pattern = Pattern.compile("正则表达式");
 * <li>创建匹配器（Matcher）:Matcher matcher = pattern.matcher("需要检查的文本");
 * <li>执行匹配操作
 * 有了 Matcher 对象后，你可以使用它来进行各种匹配操作，例如：
 * <li>find(): 搜索输入字符串以查找匹配的子序列。
 * <li>matches(): 尝试将整个区域与模式匹配。
 * <li>lookingAt(): 尝试将输入序列的开头与模式匹配。
 * <p>
 * 一些常用的正则表达式语法元素
 * <li>.: 匹配任何单个字符。
 * <li>^: 匹配输入字符串的开始位置。
 * <li>$: 匹配输入字符串的结束位置。
 * <li>*: 零次或多次匹配前面的字符或子表达式。
 * <li>+: 一次或多次匹配前面的字符或子表达式。
 * <li>?: 零次或一次匹配前面的字符或子表达式。
 * <li>[...]: 匹配方括号内的任何单个字符。
 * <li>{n}: n 是非负整数，正好匹配 n 次。
 * <li>|: 表示或操作。
 * <li>\: 转义特殊字符。
 */
public class RegularExpressionDemo {

    private static Logger logger = LoggerFactory.getLogger(RegularExpressionDemo.class);

    /**
     * 匹配13位的时间戳
     */
    public static final Pattern Timestamp13 = Pattern.compile("\\d{13}");
    public static final String REGEX = "REGEX=";

    /**
     * 是否和指定规则匹配
     *
     * @param pattern
     * @param input
     * @return
     */
    public static boolean matches(Pattern pattern, CharSequence input) {
        if (pattern == null || input == null) {
            return false;
        }
        Matcher m = pattern.matcher(input);
        return m.matches();
    }

    /**
     * <li>Pattern.CANON_EQ 当且仅当两个字符的”正规分解(canonical
     * decomposition)”都完全相同的情况下，才认定匹配.比如用了这个标志之后，表达式”a\u030A”会匹配”?”.默认情况下，不考虑”规范相等性(canonical
     * equivalence)”.
     *
     * <li>Pattern.CASE_INSENSITIVE(?i)
     * 默认情况下,大小写不明感的匹配只适用于US-ASCII字符集.这个标志能让表达式忽略大小写进行匹配.要想对Unicode字符进行大小不明感的匹
     * 配,只要将UNICODE_CASE与这个标志合起来就行了.
     *
     * <li>Pattern.COMMENTS(?x)
     * 在这种模式下,匹配时会忽略(正则表达式里的)空格字符(译者注:不是指表达式里的”\s”，而是指表达式里的空格,tab,回车之类).注释从#开始,一直到这行结束.可以通过嵌入式的标志来启用Unix行模式.
     *
     * <li>Pattern.DOTALL(?s)在这种模式下，表达式’.’可以匹配任意字符，包括表示一行的结束符。默认情况下，表达式’.’不匹配行的结束符.
     *
     * <li>Pattern.MULTILINE(?m)在这种模式下,’\^’和’$’分别匹配一行的开始和结束.此外,’^’仍然匹配字符串的开始,’$’也匹配字符串的结束.默认情况下,这两个表达式仅仅匹配字符串的开始和结束.
     *
     * <li>Pattern.UNICODE_CASE(?u)
     * 在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配.默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集.
     *
     * <li>Pattern.UNIX_LINES(?d) 在这个模式下,只有’\n’才被认作一行的中止,并且与’.’,’^’,以及’$’进行匹配.
     */
    @Test
    public void testFlag() {
        // 标志（Flags）常用标志
        // Pattern.CASE_INSENSITIVE: 忽略大小写
        // Pattern.MULTILINE: 多行模式（^和$匹配每行的开始和结束）
        // Pattern.DOTALL: 单行模式（. 匹配任何字符，包括行终止符）
        // 可以组合使用：Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
        Pattern pattern = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher("HELLO World");
        boolean found = matcher.find(); // true
        System.out.println(found);
    }


    /**
     * Pattern（模式类）：一个不可变类，代表一个已编译的正则表达式。你可以把它理解为一个“正则表达式模板”。
     * Matcher（匹配器类）：一个状态可变类，它通过一个 Pattern 实例来对目标字符串进行匹配、查找、替换等操作。它包含了匹配操作的结果。
     * <p>
     * Pattern 是编译后的正则表达式，是不可变的，线程安全。
     * Matcher 是对字符串执行匹配操作的引擎，是可变的，非线程安全。
     * 典型工作流：Pattern.compile() → pattern.matcher() → matcher.find()/matches() → matcher.group()。
     * <p>
     * 最佳实践和注意事项
     * <li>性能：如果一个正则表达式要多次使用，务必先编译成 Pattern 对象，然后重复使用。避免在循环中反复调用 Pattern.compile。
     * <li>异常处理：Pattern.compile 如果传入的正则表达式语法错误，会抛出 PatternSyntaxException。
     * <li>转义特殊字符：在 Java 字符串中，正则表达式的反斜杠需要转义，所以 \d 要写成 "\\d"。
     */
    @Test
    public void testPattern() {
        String regex = "\\d+"; // 匹配一个或多个数字
        // 将给定的正则表达式字符串编译成一个 Pattern 对象
        Pattern pattern = Pattern.compile(regex);
        // pattern() 返回正则表达式的字符串形式,其实就是返回Pattern.complile(String regex)的regex参数
        System.out.println(pattern.pattern());

        // 创建一个匹配器，该匹配器将使用此模式对给定的输入字符串进行匹配。
        Matcher matcher = pattern.matcher("123 Main St");
        // 便捷的静态方法，用于快速检查整个输入字符串是否完全匹配给定的正则表达式。适用于“一次性”的匹配检查。
        boolean isMatch = Pattern.matches("\\d+", "12345"); // true
        System.out.println(isMatch);
        isMatch = Pattern.matches("\\d+", "123abc"); // false，因为"abc"不匹配
        System.out.println(isMatch);

        // 使用此模式作为分隔符，将输入字符串分割成字符串数组。类似于 String.split 方法。
        String[] array = pattern.split("你好{123}，今天天气真好。");
        System.out.println(Arrays.toString(array));
    }


    /**
     * <h1>Matcher</h1> 匹配器类，Matcher 对象包含了匹配操作的结果和状态。
     * <p>
     * Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持.
     * <li>find()尝试查找与该模式匹配的输入序列的下一个子序列。
     * 第一次调用 find() 从字符串开头开始搜索。后续调用会从上一次匹配结束的位置开始继续搜索。
     * 如果找到，返回 true，并且可以通过 start(), end(), group() 方法获取匹配的详细信息。
     * <li>matches()是全部匹配，是将整个输入串与模式匹配,只有整个字符串都匹配了才返回true。如果要验证一个输入的数据是否为数字类型或其他类型，一般要用matches()。
     * <li>lookingAt()对前面的字符串进行匹配,只有匹配到的字符串在最前面才返回true
     */
    @Test
    public void testMatcher() {

        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher("12345");
        // matches() 尝试将整个输入序列与模式进行匹配。只有当整个字符串都匹配正则表达式时才返回 true。
        System.out.println(matcher.matches()); // true
        matcher = pattern.matcher("123abc");
        System.out.println(matcher.matches()); // false


        matcher = pattern.matcher("There are 123 apples and 456 oranges.");
        while (matcher.find()) {
            // start() 和 end() 返回上次匹配的起始索引和结束索引（结束索引是最后一个匹配字符的下一个位置）。
            System.out.println("匹配到: " + matcher.group() + "，位置 index " + matcher.start() + " to " + (matcher.end() - 1));
        }

        // lookingAt: 尝试从输入序列的开头开始与该模式匹配。与 matches 不同，它不要求匹配整个字符串，只要求从开头开始匹配。
        matcher = pattern.matcher("123abc");
        System.out.println(matcher.lookingAt()); // true，因为开头"123"匹配

        matcher = pattern.matcher("abc123");
        System.out.println(matcher.lookingAt()); // false，因为开头"abc"不匹配

        // 使用捕获组提取区号和本地号码。group() 或 group(0) 返回整个匹配的字符串。
        //group(1), group(2)... 返回第1个、第2个...捕获组的内容。
        pattern = Pattern.compile("(\\d{3})-(\\d{8})");
        matcher = pattern.matcher("Phone: 021-12345678");
        if (matcher.find()) {
            System.out.println("Full match: " + matcher.group()); // "123-4567"
            System.out.println("Area code: " + matcher.group(1)); // "123"
            System.out.println("Local number: " + matcher.group(2)); // "4567"
        }

        pattern = Pattern.compile("cat");
        matcher = pattern.matcher("one cat, two cats in the yard");
        // 替换操作
        String result = matcher.replaceAll("dog");
        System.out.println(result); // "one dog, two dogs in the yard"

        String result2 = matcher.replaceFirst("dog");
        System.out.println(result2); // "one dog, two cats in the yard"

        boolean matches = matcher.matches();
        logger.info("matcher.matches() = {}", matches);
        if (matches) {
            printMatcher(matcher);
        }

        boolean lookingAt = matcher.lookingAt();
        logger.info("matcher.lookingAt() = {}", lookingAt);
        if (lookingAt) {
            printMatcher(matcher);
        }

        // 重置匹配器:reset()方法改变了变量first 、last
        // 、oldLast、lastAppendPosition、from、to的值并将数组groups、locals初始化。
        matcher.reset();

        while (matcher.find()) {
            printMatcher(matcher);
        }

        matcher.reset();
        int groupCount = matcher.groupCount();
        logger.info("matcher.groupCount() = {}", groupCount);

    }

    /**
     * 当使用matches(),lookingAt(),find()执行匹配操作后,就可以利用以下三个方法得到更详细的信息.
     * <li>start()返回匹配到的子字符串在字符串中的索引位置.
     * <li>end()返回匹配到的子字符串的最后一个字符在字符串中的索引位置.
     * <li>group()返回匹配到的子字符串
     * <p>
     * 只有当匹配操作成功,才可以使用start(),end(),group()三个方法,否则会抛出java.lang.IllegalStateException,
     * 也就是当matches(),lookingAt(),find()其中任意一个方法返回true时,才可以使用.
     */
    public static void printMatcher(Matcher matcher) {
        System.err.println(matcher);
        System.err.println("matcher.matches() = " + matcher.matches());
        System.err.println("matcher.find() = " + matcher.find());
        System.err.println("matcher.find() = " + matcher.find());
        if (matcher.find()) {
            MatchResult matchResult = matcher.toMatchResult();
            int start = matcher.start();
            int end = matcher.end();
            String group = matcher.group();
            System.err.println("group:" + group + ",start:" + start + ",end:{}" + end);
            int groupCnt = matcher.groupCount();
            System.err.println("groupCnt:" + groupCnt);
            for (int i = 0; i < groupCnt; i++) {
                System.err.println("group" + i + ":" + matchResult.group(i));
            }
        }
    }

    /**
     * 截取所有数字，并拼接
     *
     * @param content
     * @return
     */
    public static String getAllNumbers(String content) {
        StringBuilder stringBuilder = new StringBuilder();
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
            stringBuilder.append(matcher.group(0));
        }
        return stringBuilder.toString();
    }

    /**
     * 截取第一次匹配到的数字
     *
     * @param content
     * @return
     */
    public static String getFirstNumbers(String content) {
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            System.out.println(matcher.group());
            return matcher.group();
        }
        return "";
    }

    @Test
    public void test() {
        Pattern pattern = Pattern.compile("\\s*[|]+\\s*");
        String[] array = pattern.split("a|b|c | d  | e");
        logger.info("{}", Arrays.toString(array));
    }

    /**
     * 用正则表达式
     *
     * @param str
     * @return
     */
    public static boolean isNumeric2(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }

    @Test
    public void noCaptureGroup() {
        Pattern pattern = Pattern.compile("(?:(\\d+))?\\s?([a-zA-Z]+)?.+");
        String source = "2133 fdsdee4333";
        Matcher matcher = pattern.matcher(source);
        if (matcher.matches()) {
            for (int i = 0; i <= matcher.groupCount(); i++) {
                System.out.println("group " + i + ":" + matcher.group(i));
            }
        }
    }

    @Test
    public void atomicGroup() {
        Pattern pattern = Pattern.compile("(\\d+)\\s+(?>bc|b)(\\w)");
        String source = "543543   bcc"; // 而“543543 bc” 却匹配失败因为bc已经被原子分组匹配了，当(\\w)进行匹配的时候前面的分组由于是贪婪型匹配所以不会突出以匹配的字符
        Matcher matcher = pattern.matcher(source);
        if (matcher.matches()) {
            for (int i = 0; i <= matcher.groupCount(); i++) {
                System.out.println("group " + i + ":" + matcher.group(i));
            }
        }
    }

    /**
     * 什么是捕获组？捕获组是正则表达式中用括号 () 括起来的部分，它们可以"捕获"匹配的文本，后续可以通过组号来引用。
     * group是针对()来说的，group（0）就是指的整个串，group（1） 指的是第一个括号里的东西，group（2）指的第二个括号里的东西。
     * 组号分配规则：组号按照左括号的出现顺序分配
     * <li> (A)((B)(C(D))) - 组号分配：
     * <li> 组1: A
     * <li> 组2: (B)(C(D)) - 整个外层括号
     * <li> 组3: B
     * <li> 组4: C(D)
     * <li> 组5: D
     */
    @Test
    public void testGroup() {
        // 括号创建了捕获组
        String dateStr = "Today is 2024-03-15";
        Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
        Matcher matcher = pattern.matcher(dateStr);

        if (matcher.find()) {
            System.out.println("完整日期: " + matcher.group());    // "2024-03-15"
            System.out.println("年: " + matcher.group(1));        // "2024"
            System.out.println("月: " + matcher.group(2));        // "03"
            System.out.println("日: " + matcher.group(3));        // "15"
        }
        // 嵌套捕获组
        String input = "区域: (86) 138-0013-8000";
        // 外层分组: 整个电话号码
        // 内层分组: 国家代码、前缀、主要号码
        pattern = Pattern.compile("区域: \\((\\d+)\\) (\\d+)-(\\d+)-(\\d+)");
        matcher = pattern.matcher(input);

        if (matcher.find()) {
            System.out.println("整个匹配: " + matcher.group());    // "区域: (86) 138-0013-8000"
            System.out.println("国家代码: " + matcher.group(1));   // "86"
            System.out.println("前缀: " + matcher.group(2));       // "138"
            System.out.println("主要号码第一部分: " + matcher.group(3)); // "0013"
            System.out.println("主要号码第二部分: " + matcher.group(4)); // "8000"
        }

        // Java 7 引入了命名捕获组，语法为 (?<name>...)：
        String url = "https://www.example.com:8080/path/to/page";
        pattern = Pattern.compile("(https?)://([^:/]+)(?::(\\d+))?(/.*)?");
        matcher = pattern.matcher(url);

        if (matcher.find()) {
            System.out.println("协议: " + matcher.group(1));      // "https"
            System.out.println("域名: " + matcher.group(2));      // "www.example.com"
            System.out.println("端口: " + matcher.group(3));      // "8080"（可能为null）
            System.out.println("路径: " + matcher.group(4));      // "/path/to/page"
        }

        // 使用命名捕获组 - 语法: (?<name>pattern)
        pattern = Pattern.compile(
                "(?<protocol>https?)://" +           // 协议
                        "(?<domain>[^:/]+)" +                // 域名
                        "(?::(?<port>\\d+))?" +              // 端口（可选）
                        "(?<path>/.*)?"                      // 路径（可选）
        );

        matcher = pattern.matcher(url);

        if (matcher.find()) {
            // 使用命名组 - 代码更清晰易读
            System.out.println("协议: " + matcher.group("protocol"));  // "https"
            System.out.println("域名: " + matcher.group("domain"));    // "www.example.com"
            System.out.println("端口: " + matcher.group("port"));      // "8080"
            System.out.println("路径: " + matcher.group("path"));      // "/path/to/page"

            System.out.println("\n--- 仍然可以使用数字索引 ---");
            System.out.println("组1 (protocol): " + matcher.group(1));  // "https"
            System.out.println("组2 (domain): " + matcher.group(2));    // "www.example.com"
            System.out.println("组3 (port): " + matcher.group(3));      // "8080"
            System.out.println("组4 (path): " + matcher.group(4));      // "/path/to/page"
        }
    }

    /**
     * 如果  pattern 是正则表达式，则使用正则匹配；否则，直接比较字符串
     *
     * @param pattern
     * @param value
     * @return
     */
    public static boolean matchValue(String pattern, String value) {
        if (pattern == null || value == null) {
            return false;
        }
        if (pattern.startsWith(REGEX)) {
            return Pattern.matches(pattern.substring(REGEX.length()), value);
        }
        return StringUtils.equals(value, pattern);
    }

    @Test
    public void demo3() {
        Pattern p = Pattern.compile("\\d+");
        Matcher m = p.matcher("我的QQ是:456456 我的电话是:0532214 我的邮箱是:aaa123@aaa.com");
        while (m.find()) {
            System.out.println(m.group());
            System.out.print("start:" + m.start());
            System.out.println(" end:" + m.end());
        }
    }

    @Test
    public void test4() {
        String a = "a;b;z；d;e；y";
        String[] array = a.split(";|；");
        for (String string : array) {
            System.out.println(string);
        }
    }

    /**
     * | 将两个匹配条件进行逻辑“或”（Or）运算。
     */
    @Test
    public void test2() {
        System.out.println("|DF|A3".split("|").length);
        String[] array = "|DF|A3".split("");
        for (String string : array) {
            System.out.printf("%s ,", string);
        }
        System.out.println("-------------------------");
        String[] array2 = "|DF|A3".split("|");
        for (String string : array2) {
            System.out.printf("%s ,", string);
        }

        System.out.println("-------------------------");
        String[] array3 = "abcdefghijklmnopqrstuvwxyyz0123456789".split("");
        for (String string : array3) {
            System.out.printf("%s ,", string);
        }
        System.out.println("-------------------------");
        System.out.println("|DF|A3".split("\\|").length);
    }

    @Test
    public void test3() {
        // * 匹配前面的子表达式零次或多次
        System.out.println("ac.matches(a*b*c) = " + "ac".matches("a*b*c"));
        System.out.println("ac.matches(a*b*c) = " + "ac".matches("a*b*c"));
        System.out.println("a*b*c.matches(a*b*c) = " + "a*b*c".matches("a*b*c"));
        System.out.println("abc.matches(a*b*c) = " + "abc".matches("a*b*c"));
        System.out.println("bbc.matches(a*b*c) = " + "bbc".matches("a*b*c"));
        System.out.println("zbc.matches(a*b*c) = " + "zbc".matches("a*b*c"));
        System.out.println("aaaaaaa.pro".matches(".*pro$"));
        System.out.println("He's a weasel".matches(".*weasel$"));
        System.out.println("z".matches("zo*"));
        System.out.println("zo".matches("zo*"));
        System.out.println("zoo".matches("zo*"));
    }

    @Test
    public void test1() {
        String string = "33,你好,88";
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(string);
        System.out.println("matcher.matches() = " + matcher.matches());

        while (matcher.find()) {
            String tmp = matcher.group(0);
            System.out.println(tmp);
        }
        //
        boolean isMatched = matcher.matches();
        System.out.println("是否全部匹配：" + isMatched);
        boolean isLooked = matcher.lookingAt();
        System.out.println("是否开头匹配：" + isLooked);

        int groupCount = matcher.groupCount();
        System.out.println(groupCount);
    }

    // 判断一个字符串是否都为数字
    public static boolean isDigit2(String strNum) {
        Pattern pattern = Pattern.compile("[0-9]{1,}");
        Matcher matcher = pattern.matcher(strNum);
        return matcher.matches();
    }

    @Test
    public void testEmail() {
        // 定义邮箱的正则表达式
        String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";

        Pattern pattern = Pattern.compile(emailRegex);
        String emailToCheck = "example@example.com";
        Matcher matcher = pattern.matcher(emailToCheck);

        if (matcher.matches()) {
            System.err.println(emailToCheck + " 是有效的邮箱地址。");
        } else {
            System.err.println(emailToCheck + " 不是有效的邮箱地址。");
        }
    }

    @Test
    public void testOr() {
        String pattern = "(日出|日落|海洋)";
        Pattern regex = Pattern.compile(pattern);

        // 测试字符串
        String text = "我们在海洋边看日出和日落。";
        Matcher matches = regex.matcher(text);
        printMatcher(matches);

    }

    // 截取非数字
    public static String splitNotNumber(String content) {
        Pattern pattern = Pattern.compile("\\D+");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            return matcher.group(0);
        }
        return "";
    }
    // 判断一个字符串是否含有数字

    public static boolean hasDigit(String content) {
        boolean flag = false;
        Pattern p = Pattern.compile(".*\\d+.*");
        Matcher m = p.matcher(content);
        if (m.matches()) {
            flag = true;
        }
        return flag;
    }

    /**
     * matches 方法尝试将整个输入字符串与模式进行匹配。
     * 如果整个输入字符串与模式匹配成功，则返回 true；否则返回 false。
     */
    @Test
    public void testMatches() {
        // 定义正则表达式
        String regex = "\\d+"; // 匹配一个或多个数字

        System.out.println(Pattern.matches(regex, "2"));

        System.out.println(Pattern.matches(regex, "20"));

        System.out.println(Pattern.matches(regex, " "));

        System.out.println(Pattern.matches(regex, "1 2 3 4 "));

        System.out.println(Pattern.matches(regex, "abcd"));
    }

    // 判断一个字符串是否都为数字
    public static boolean isDigit(String strNum) {
        return strNum.matches("[0-9]{1,}");
    }

    @Test
    public void testSplit() {

        System.out.println("-------,测试--------");
        String text = "apple,banana,orange,pear";
        Pattern pattern = Pattern.compile(",");
        String[] result = pattern.split(text);
        System.err.println(Arrays.toString(result));


        System.out.println("-------\\d+测试--------");
        String text1 = "1234,banana,2234,pear";
        Pattern pattern1 = Pattern.compile("\\d+");
        String[] result1 = pattern1.split(text1);
        System.err.println(Arrays.toString(result1));

        System.out.println("-------\\d测试--------");
        String text2 = "1234,banana,2234,pear";
        Pattern pattern2 = Pattern.compile("\\d");
        String[] result2 = pattern2.split(text2);
        System.err.println(Arrays.toString(result2));

    }


    @Test
    public void testMatchValue() {
        String pattern = "REGEX=(Failed|FailedCreate|FailedKillPod|FailedScheduling|FailedPreStopHook)";
        System.out.println(matchValue(pattern, "Failed"));
        System.out.println(matchValue(pattern, "FailedCreate"));

        pattern = "REGEX=(ZX_Down|ZX_BW_Usage|ZX_PacketDiscards|NAT_BW_Usage)";
        System.out.println(matchValue(pattern, "ZX_PacketDiscards"));
    }

    /**
     * find()和group()方法是搭配起来使用的。
     * <li>find 方法在输入字符串中查找下一个匹配的子序列。 如果找到匹配的子序列，则返回 true；否则返回 false。
     * <li>group 方法返回当前匹配的子序列。如果在调用 matches、find 等方法后找到了匹配的子序列，可以使用 group 方法获取匹配的内容。
     * <li>start 方法返回当前匹配的子序列的起始索引。
     * <li>end 方法返回当前匹配的子序列的结束索引。
     * <li>reset 方法将 Matcher 对象的状态重置，使其可以重新在输入字符串中进行匹配。在重复使用 Matcher 对象进行匹配时，可以使用 reset ()方法清除之前的匹配状态
     */
    @Test
    public void testFind() {
        String input = "Hello, my age is 25 and my friend's age is 30.";

        // 定义正则表达式
        String regex = "\\d+"; // 匹配一个或多个数字

        // 编译正则表达式为 Pattern 对象
        Pattern pattern = Pattern.compile(regex);

        // 创建 Matcher 对象，并使用正则表达式匹配输入字符串
        Matcher matcher = pattern.matcher(input);

        // 查找匹配的数字
        while (matcher.find()) {
            System.out.println("Found: " + matcher.group());
        }
    }

    @Test
    public void testPod2App() {
        String pod = "content-process-upload-service-b57ddbb4d-9pxmr";
        String regex = "(.*)-.*-.*";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(pod);

        printMatcher(matcher);
        if (matcher.find()) {
            // group(0) 或 group(): 返回整个匹配的字符串
            System.err.println(matcher.group());
            System.err.println(matcher.group(0));
            // group(1) 返回相应的捕获组
            System.err.println(matcher.group(1));
        }

    }

    @Test
    public void testRegexGroupCount() {
        // 原始的正则表达式
        String pattern1 = "(.*)-.*-.*";
        showGroupCount(pattern1);

        // 包含多个捕获组的正则表达式
        String pattern2 = "(\\w+)-(\\w+)-(\\w+)";
        showGroupCount(pattern2);

        // 包含非捕获组的正则表达式
        String pattern3 = "(\\w+)(?:-(\\w+))+";
        showGroupCount(pattern3);
    }

    private static void showGroupCount(String patternString) {
        Pattern pattern = Pattern.compile(patternString);
        int count = pattern.matcher("").groupCount();
        System.err.println("正则表达式: " + patternString);
        System.err.println("捕获组数量: " + count);
        System.err.println();
    }

    @Test
    public void testPromTemplate() {
        String template = "{{ $labels.instance }} 的当前值是  {{ $value }}, 报警应用 {{$labels.app}}, 所属集群 {{$labels.cluster}}";
        Map<String, String> tags = new HashMap<>();
        tags.put("instance", "127.0.0.1");
        tags.put("app", "demo-app");
        double value = 0.75;
        System.out.println(parseTemplate(template, tags, value));
    }

    private static final Pattern LABEL_PATTERN = Pattern.compile("\\{\\{\\s*\\$labels\\.(\\w+)\\s*\\}\\}");
    private static final Pattern VALUE_PATTERN = Pattern.compile("\\{\\{\\s*\\$value\\s*\\}\\}");

    /**
     * 解析 Prometheus 模板字符串
     *
     * @param template 模板字符串，如 "{{ $labels.instance }} 当前值：{{ $value }}"
     * @param labels   标签映射
     * @param value    指标值
     * @return 解析后的字符串
     */
    public static String parseTemplate(String template, Map<String, String> labels, double value) {
        if (template == null) {
            return "";
        }

        String result = template;

        // 1. 解析 {{ $labels.xxx }} 格式

        Matcher labelMatcher = LABEL_PATTERN.matcher(result);

        while (labelMatcher.find()) {
            String labelName = labelMatcher.group(1);
            String labelValue = labels.getOrDefault(labelName, " ");
            String g0 = labelMatcher.group(0);
            result = result.replace(g0, labelValue);
            labelMatcher = LABEL_PATTERN.matcher(result); // 重置matcher
        }

        // 2. 解析 {{ $value }} 格式

        Matcher valueMatcher = VALUE_PATTERN.matcher(result);

        while (valueMatcher.find()) {
            String formattedValue = formatValue(value);
            result = result.replace(valueMatcher.group(0), formattedValue);
            valueMatcher = VALUE_PATTERN.matcher(result); // 重置matcher
        }

        return result;
    }

    /**
     * 格式化数值显示
     */
    private static String formatValue(double value) {
        // 如果是整数，显示为整数格式
        if (value == (long) value) {
            return String.valueOf((long) value);
        }
        // 否则保留两位小数
        return String.format("%.2f", value);
    }
}
